﻿// BoostAsioTcp.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <stdio.h>
#include <iostream>

#include <boost/shared_ptr.hpp>    
#include <boost/thread.hpp>    
#include <boost/thread/mutex.hpp>    
#include <boost/lambda/lambda.hpp>  
#include <boost/asio.hpp>    
#include <boost/asio/placeholders.hpp>    
#include <boost/system/error_code.hpp>    
#include <boost/bind/bind.hpp> 

using namespace boost;
using namespace boost::asio;

typedef boost::mutex CMutex;
CMutex muConsole;//互斥访问控制台 

//可变参数列表函数  
void ConsoleOutput(bool bClient, const char* lpszFmt, ...) {
	//主线程输出：FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE  
	//客户端线程输出：FOREGROUND_RED  
	//服务器线程输出：FOREGROUND_GREEN  
	va_list pArgLst;

	va_start(pArgLst, lpszFmt);
	muConsole.lock();

	if (bClient)     
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);
	else                
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);
	
	vfprintf(stdout, lpszFmt, pArgLst);
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
	muConsole.unlock();
	va_end(pArgLst);
}

class CServer {
	typedef CServer this_type;
	typedef ip::tcp::acceptor CAcceptor;
	typedef ip::tcp::endpoint CEndPt;
	typedef ip::tcp::socket CSocket;
	typedef ip::address CAddr;
	typedef boost::shared_ptr<CSocket> CSocketPtr;

private:
	int iClients;
	io_service oIoSrv;//使用io_service同操作系统的输入/输出服务进行交互
	CAcceptor oAcceptor;//接收器，接收客户端连接
public:

	CServer() : oAcceptor(oIoSrv, CEndPt(ip::tcp::v4(), 5432))
	{
		//初始化一个io_service
		iClients = 0; Accept();
	}
	
	void Run()
	{
		oIoSrv.run();//相关联的句柄也会在同一个线程内被执行
	}
	
	void Accept()
	{
		CSocketPtr poSock(new CSocket(oIoSrv));
		//异步非阻塞
		//进行异步绑定，在bind中调用成员函数AcceptHandler ，参数为error 与poSock
		oAcceptor.async_accept(*poSock,
			boost::bind(&CServer::AcceptHandler,
				this,
				boost::asio::placeholders::error,
				poSock));
	}
	
	void AcceptHandler(const boost::system::error_code& errorcode, CSocketPtr& sock)
	{
		if (errorcode)
			return;
		ConsoleOutput(
			//控制台输出 获取客户端主机地址
			false,
			"RemoteClient : %s\n",
			sock->remote_endpoint().address().to_string().c_str());
		
		//向客户端进行写入，异步
		sock->async_write_some(
			buffer("Hello, Client"),
			boost::bind(
				&CServer::WriteHandler,
				this,
				boost::asio::placeholders::error));
		
		iClients++;
		
		//发送完毕后继续监听，否则io_service将认为没有事件处理而结束运行  
		if (iClients < 10)
			Accept();
	}

	void WriteHandler(const boost::system::error_code& errorcode)
	{
		ConsoleOutput(false, "Send Msg Successfully !\n");
	}
};

class CClient {
	typedef CClient this_type;
	typedef ip::tcp::acceptor CAcceptor;
	typedef ip::tcp::endpoint CEndPt;
	typedef ip::tcp::socket CSocket;
	typedef ip::address CAddr;
	typedef boost::shared_ptr<CSocket> CSocketPtr;

private:
	io_service oIoSrv;
	char szBuffer[64];
	CEndPt oEndPt;

public:

	//客户端初始化绑定服务端地址和监听端口
	CClient(const char* lpszAddr) : oEndPt(CAddr::from_string(lpszAddr), 5432)
	{
		Start();
	}

	void Run() { oIoSrv.run(); }

	void Start()
	{
		CSocketPtr poSock(new CSocket(oIoSrv));
		//连接服务端
		poSock->async_connect
		(
			oEndPt,
			//在bind中调用成员函数ConnHandler
			boost::bind(
				&CClient::ConnHandler,
				this,
				boost::asio::placeholders::error, poSock)
		);
	}

	void ConnHandler(const boost::system::error_code& errorcode, CSocketPtr& sock) {
		if (errorcode)
			return;
		//显示服务端信息
		ConsoleOutput(true, "Recv From %s : ",
			sock->remote_endpoint().address().to_string().c_str());
		//读取服务端写入的信息
		sock->async_read_some(buffer(szBuffer),
			boost::bind(
				&CClient::ReadHandler,
				this,
				boost::asio::placeholders::error, sock));
	}

	void ReadHandler(const boost::system::error_code& errorcode, CSocketPtr& sock)
	{
		if (errorcode)
			return;
		sock->async_read_some(
			buffer(szBuffer),
			boost::bind(
				&CClient::ReadHandler,
				this,
				boost::asio::placeholders::error, sock)
		);
		ConsoleOutput(true, "%s\n", szBuffer);
	}
};

void ServerAccept() { CServer oServer; oServer.Run(); }

void Client1Connect() { CClient oClient("127.0.0.1"); oClient.Run(); }

void Client2Connect() { CClient oClient("10.0.0.23"); oClient.Run(); }

int main()
{
	std::thread oServerThread(ServerAccept);//服务端线程
	std::thread oClientThread1(Client1Connect);//客户端线程

	oClientThread1.join();
	std::cout << "ClientThread1Exits\n";

	//std::thread oClientThread2(Client2Connect);//启动客户端线程   
	//oClientThread2.join();
	//std::cout << "ClientThread2Exits\n";


	oServerThread.join();
	std::cout << "ServerThreadExits\n";

	std::cin.get();
}


